%%-*- mode: erlang -*-
%% emqx_auth_redis config mapping

{mapping, "auth.redis.type", "emqx_auth_redis.server", [
  {default, single},
  {datatype, {enum, [single, sentinel, cluster]}}
]}.

{mapping, "auth.redis.server", "emqx_auth_redis.server", [
  {default, "127.0.0.1:6379"},
  {datatype, [string]}
]}.

{mapping, "auth.redis.sentinel", "emqx_auth_redis.server", [
  {default, ""},
  {datatype, string},
  hidden
]}.

{mapping, "auth.redis.pool", "emqx_auth_redis.server", [
  {default, 8},
  {datatype, integer}
]}.

{mapping, "auth.redis.database", "emqx_auth_redis.server", [
  {default, 0},
  {datatype, integer}
]}.

{mapping, "auth.redis.password", "emqx_auth_redis.server", [
  {default, ""},
  {datatype, string},
  hidden
]}.

{mapping, "auth.redis.ssl.enable", "emqx_auth_redis.options", [
  {default, off},
  {datatype, flag}
]}.

{mapping, "auth.redis.ssl.cacertfile", "emqx_auth_redis.options", [
  {datatype, string}
]}.

{mapping, "auth.redis.ssl.certfile", "emqx_auth_redis.options", [
  {datatype, string}
]}.

{mapping, "auth.redis.ssl.keyfile", "emqx_auth_redis.options", [
  {datatype, string}
]}.

{mapping, "auth.redis.ssl.verify", "emqx_auth_redis.options", [
  {default, false},
  {datatype, {enum, [true, false]}}
]}.

{mapping, "auth.redis.ssl.server_name_indication", "emqx_auth_redis.options", [
  {datatype, string}
]}.

%% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
{mapping, "auth.redis.cafile", "emqx_auth_redis.options", [
  {datatype, string}
]}.

%% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
{mapping, "auth.redis.certfile", "emqx_auth_redis.options", [
  {datatype, string}
]}.

%% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
{mapping, "auth.redis.keyfile", "emqx_auth_redis.options", [
  {datatype, string}
]}.

{translation, "emqx_auth_redis.options", fun(Conf) ->
   Ssl = cuttlefish:conf_get("auth.redis.ssl.enable", Conf, false),
   Filter  = fun(Opts) -> [{K, V} || {K, V} <- Opts, V =/= undefined] end,
   case Ssl of
       true ->
           %% FIXME: compatible with 4.0-4.2 version format, plan to delete in 5.0
           CA = cuttlefish:conf_get(
                    "auth.redis.ssl.cacertfile", Conf,
                    cuttlefish:conf_get("auth.redis.cafile", Conf, undefined)
                ),
           Cert = cuttlefish:conf_get(
                    "auth.redis.ssl.certfile", Conf,
                    cuttlefish:conf_get("auth.redis.certfile", Conf, undefined)
                  ),
           Key = cuttlefish:conf_get(
                    "auth.redis.ssl.keyfile", Conf,
                    cuttlefish:conf_get("auth.redis.keyfile", Conf, undefined)
                 ),
           Verify = case cuttlefish:conf_get("auth.redis.ssl.verify", Conf, false) of
                         true -> verify_peer;
                         false -> verify_none
                     end,
           SNI = case cuttlefish:conf_get("auth.redis.ssl.server_name_indication", Conf, undefined) of
                   "disable" -> disable;
                   SNI0 -> SNI0
                 end,
           [{options, [{ssl_options,
                        Filter([{cacertfile, CA},
                                {certfile, Cert},
                                {keyfile, Key},
                                {verify, Verify},
                                {server_name_indication, SNI}
                               ])
                       }]}];
       _ -> [{options, []}]
   end
end}.

{translation, "emqx_auth_redis.server", fun(Conf) ->
  Fun = fun(S) ->
    case string:split(S, ":", trailing) of
      [Domain]       -> {Domain, 6379};
      [Domain, Port] -> {Domain, list_to_integer(Port)}
    end
  end,
  Servers = cuttlefish:conf_get("auth.redis.server", Conf),
  Type = cuttlefish:conf_get("auth.redis.type", Conf),
  Server = case Type of
    single ->
      {Host, Port} = Fun(Servers),
      [{host, Host}, {port, Port}];
    _ ->
      S = string:tokens(Servers, ","),
      [{servers, [Fun(S1) || S1 <- S]}]
  end,
  Pool = cuttlefish:conf_get("auth.redis.pool", Conf),
  Passwd = cuttlefish:conf_get("auth.redis.password", Conf),
  DB = cuttlefish:conf_get("auth.redis.database", Conf),
  Sentinel = cuttlefish:conf_get("auth.redis.sentinel", Conf),
  [{type, Type},
   {pool_size, Pool},
   {auto_reconnect, 1},
   {database, DB},
   {password, Passwd},
   {sentinel, Sentinel}] ++ Server
end}.

{mapping, "auth.redis.query_timeout", "emqx_auth_redis.query_timeout", [
  {default, ""},
  {datatype, string}
]}.

{translation, "emqx_auth_redis.query_timeout", fun(Conf) ->
  case cuttlefish:conf_get("auth.redis.query_timeout", Conf) of
      "" -> infinity;
      Duration ->
          case cuttlefish_duration:parse(Duration, ms) of
              {error, Reason} -> error(Reason);
              Ms when is_integer(Ms) -> Ms
          end
  end
end}.

{mapping, "auth.redis.auth_cmd", "emqx_auth_redis.auth_cmd", [
  {datatype, string}
]}.

{mapping, "auth.redis.password_hash", "emqx_auth_redis.password_hash", [
  {datatype, string}
]}.

{mapping, "auth.redis.super_cmd", "emqx_auth_redis.super_cmd", [
  {datatype, string}
]}.

{mapping, "auth.redis.acl_cmd", "emqx_auth_redis.acl_cmd", [
  {datatype, string}
]}.

{translation, "emqx_auth_redis.password_hash", fun(Conf) ->
  HashValue = cuttlefish:conf_get("auth.redis.password_hash", Conf),
  case string:tokens(HashValue, ",") of
    [Hash]           -> list_to_atom(Hash);
    [Prefix, Suffix] -> {list_to_atom(Prefix), list_to_atom(Suffix)};
    [Hash, MacFun, Iterations, Dklen] -> {list_to_atom(Hash), list_to_atom(MacFun), list_to_integer(Iterations), list_to_integer(Dklen)};
    _                -> plain
  end
end}.
